# -*- coding = utf-8 -*-
# @Time : 2023/5/29 10:20
# @Author : GHHHHHHHHH
# @File : viewService.py
# @Software : PyCharm
import base64
import os
import random
import signal
import urllib
from collections import Counter
from threading import Thread

import numpy as np
import psutil
import requests
from scipy.optimize import leastsq

from dao import AlgorithmDao
from utils.ftp_util import FTP
from utils.json_open_close import open_json

thread_flag = True


class AlgorithmService:
    @staticmethod
    def select_username(username):
        return AlgorithmDao.select_username(username)

    @staticmethod
    def ocr(image_file):
        image_file = base64.b64encode(image_file).decode("utf8")
        image_file = urllib.parse.quote_plus(image_file)
        API_KEY = "shy5nQA09cLT6ZqkzNWHkapS"
        SECRET_KEY = "jxi1cxSG4MaMKx1BGycSMCLT0AlISDkB"
        url = "https://aip.baidubce.com/oauth/2.0/token"
        params = {"grant_type": "client_credentials", "client_id": API_KEY, "client_secret": SECRET_KEY}
        url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token=" + str(
            requests.post(url, params=params).json().get("access_token"))

        payload = f"image={image_file}"
        headers = {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Accept': 'application/json'
        }
        response = requests.request("POST", url, headers=headers, data=payload)
        return eval(response.text)['words_result'][0]['words']

    @staticmethod
    def plate_start():
        # 开启识别模型
        def start_thread():
            os.system(
                "conda activate car && cd F:\Python projects\YOLOv5-LPRNet-Licence-Recognition-master && python main.py --source=0")

        t = Thread(target=start_thread)
        t.start()
        return {
            "status": "success"
        }

    @staticmethod
    def plate_end():
        def end_thread():
            pids = psutil.process_iter()
            pid_stack = []
            for pid in pids:
                if pid.name() == "python.exe":
                    pid_stack.append(pid.pid)
            pid_stack.remove(os.getpid())
            os.kill(max(pid_stack), signal.SIGINT)

        t = Thread(target=end_thread)
        t.start()
        return {
            "status": "success"
        }

    @staticmethod
    def save_plate(plate):
        """
        保存车牌号
        :param plate: 车牌号 string格式
        :return:
        """
        # 如果是已知的车辆
        if AlgorithmDao.ensure_is_registeration(plate):
            # 设置为已知
            is_registeration = 1
            # 查询司机id
            driver_id = AlgorithmDao.select_driver_id_by_car_number(plate)[0]['driver_id']
        else:
            # 设置为未知
            is_registeration = 0
            driver_id = None
        if AlgorithmDao.save_plate(plate, is_registeration, driver_id):
            return {
                "status": "success"
            }
        else:
            return {
                "status": "failed"
            }

    @staticmethod
    def bayonet_msg(user_id):
        # 根据用户id获取卡口信息
        try:
            data = AlgorithmDao.bayonet_msg(user_id)
            if len(data) == 0:
                return {
                    "status": "failed",
                    "data": {
                        "Error": "Message not found"
                    }
                }
            return {
                "status": "success",
                "data": data
            }
        except Exception as e:
            return {
                "status": "failed",
                "data": {
                    "Error": f"{e}"
                }
            }

    @staticmethod
    def bayonet_passed_company(bayonet_id):
        # 根据卡口id获取通过属于公司的车辆信息
        try:
            return {
                "status": "success",
                "data": AlgorithmDao.bayonet_passed_company(bayonet_id)
            }
        except Exception as e:
            return {
                "status": "failed",
                "data": {
                    "Error": f"{e}"
                }
            }

    @staticmethod
    def bayonet_passed_private(bayonet_id):
        # 根据卡口id获取通过不属于公司的车辆信息
        try:
            return {
                "status": "success",
                "data": AlgorithmDao.bayonet_passed_private(bayonet_id)
            }
        except Exception as e:
            return {
                "status": "failed",
                "data": {
                    "Error": f"{e}"
                }
            }

    @staticmethod
    def bayonet_get_driver(car_number, passed_time):
        # 根据车牌号获取司机信息
        try:
            data = AlgorithmDao.bayonet_get_driver(car_number, passed_time)
            if len(data) == 0:
                return {
                    "status": "failed",
                    "data": "message not found"
                }
            return {
                "status": "success",
                "data": data
            }
        except Exception as e:
            return {
                "status": "failed",
                "data": {
                    "Error": f"{e}"
                }
            }

    @staticmethod
    def infoDep_infoDep():
        def model_res(yi, number):
            """
            :param yi: y值
            :param number: 要预测的值数目
            :return: 预测的列表
            """

            def func(p, x):
                k1, k2, b = p
                return k1 * x ** 2 + k2 * x + b

            def error(p, x, y):
                return func(p, x) - y

            yi = np.array(yi)
            p0 = [1, 1, 1]
            length = len(yi)
            Para = leastsq(error, p0, args=(np.array([i for i in range(1, length + 1)]), yi))
            return [abs(int(item)) for item in
                    func(Para[0], np.array([i for i in range(length + 1, length + 1 + number)]))]

        carPerDay = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
        disfunctionalNum = [5, 4, 2, 8, 7, 9, 6, 1, 2, 3]
        return {
            "status": 200,
            'data': {
                'day': 10,
                'carPerDay': carPerDay,
                "disfunctionalNum": disfunctionalNum,
                "futureDay": 3,
                "futureCarForcast": model_res(carPerDay, 3),
                "futuredisfunctionalForcast": model_res(disfunctionalNum, 3)
            },
            "message": "succeed"
        }

    @staticmethod
    def baidu_map_get_place(l1, l2):
        url = f"https://api.map.baidu.com/reverse_geocoding/v3/?ak=wEL2BWR51pG3CpgO3BgpmCfOAkvWm5E5&location={l1},{l2}&output=json&coordtype=wgs84ll"
        headers = {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Accept': 'application/json',

        }
        response = requests.request("POST", url, headers=headers)
        return response.json()

    @staticmethod
    def infoDep_pieChart():
        # 库存车辆占比API
        try:
            car_type_message = AlgorithmDao.infoDep_pieChart()
            car_type_message = dict(Counter([item['motorcycle_type'] for item in car_type_message]))
            return {
                "status": 200,
                "message": "succeed",
                "data": {
                    "typeNum": len(list(car_type_message.keys())),
                    "typeName": list(car_type_message.keys()),
                    "typeValue": list(car_type_message.values())
                }
            }
        except Exception as e:
            return {
                "status": 400,
                "message": f"{e}"
            }

    @staticmethod
    def infoDep_ledarChart():
        # 返回一周内的数据
        # 出车量
        carNum = len(AlgorithmDao.get_carNum())
        # 里程数
        mile = sum([item['mile'] for item in AlgorithmDao.get_mile()])
        # 卡口车流量
        flow = len(AlgorithmDao.get_flow())
        # 上工率
        shangGongRate = len(set(AlgorithmDao.get_shang_gong_num())) / len(AlgorithmDao.get_driver_num())
        # 违章率
        weiZhangRate = float(random.uniform(0, 0.3).__format__(".2"))
        return {
            "carNum": carNum,
            "mile": mile,
            "flow": flow,
            "shangGongRate": shangGongRate,
            "weiZhangRate": weiZhangRate,
            "max_carNum": int(carNum * random.uniform(1.0, 1.5)),
            "max_mile": int(mile * random.uniform(1.0, 1.5)),
            "max_flow": int(flow * random.uniform(1.0, 1.5)),
            "max_shangGongRate": float(random.uniform(shangGongRate, 1.0).__format__('.2')),
            "max_weiZhangRate": float(random.uniform(weiZhangRate, 0.4).__format__('.2'))
        }

    @staticmethod
    def get_info_msg():
        try:
            data = open_json("static/msg.json")
        except Exception as e:
            return {
                "status": 400,
                "message": f"{e}"
            }
        random.shuffle(data)
        return {
            "status": 200,
            "message": data[0]
        }

    @staticmethod
    def get_car(currentpage, pagesize, is_registration):
        try:
            data = AlgorithmDao.get_car(is_registration)
            length = len(data)
            data = [data[i:i + pagesize] for i in range(0, len(data), pagesize)]
            return {
                "status": "succeed",
                "data": {
                    "total": length,
                    "list": data[currentpage - 1]
                }
            }
        except Exception as e:
            return {
                "status": f"{e}",
                "data": {
                    "total": None,
                    "data": []
                }
            }

    @staticmethod
    def ftp_server(image, _id):
        filetype = str(image).split('/')[1].split("'")[0]
        if filetype not in ('jpg', 'png'):
            return {
                "status": 400,
                "message": "image type must be 'jpg' or 'png'."
            }
        filename = str(_id) + '.' + filetype
        try:
            ftp = FTP()
            ftp.upload(image, filename)
            ftp.close()
        except Exception as e:
            return {
                "status": 400,
                "message": f"{e}"
            }
        try:
            _id, _ = filename.split('.')
            AlgorithmDao.ftp_server(int(_id), filename)
            return {
                "status": 200,
                "message": 'succeed'
            }
        except Exception as e:
            return {
                "status": 400,
                "message": f"{e}"
            }
